home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / cc / g++-dist / collect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-23  |  15.9 KB  |  687 lines

  1. /* Output tables which say what global initializers need
  2.    to be called at program startup, and what global destructors
  3.    need to be called at program termination, for GNU C++ compiler.
  4.    Copyright (C) 1987 Free Software Foundation, Inc.
  5.    Hacked by Michael Tiemann (tiemann@mcc.com)
  6.    COFF Changes by Dirk Grunwald (grunwald@flute.cs.uiuc.edu)
  7.  
  8. This file is part of GNU CC.
  9.  
  10. GNU CC is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY.  No author or distributor
  12. accepts responsibility to anyone for the consequences of using it
  13. or for whether it serves any particular purpose or works at all,
  14. unless he says so in writing.  Refer to the GNU CC General Public
  15. License for full details.
  16.  
  17. Everyone is granted permission to copy, modify and redistribute
  18. GNU CC, but only under the conditions described in the
  19. GNU CC General Public License.   A copy of this license is
  20. supposed to have been given to you along with GNU CC so you
  21. can know your rights and responsibilities.  It should be in a
  22. file named COPYING.  Among other things, the copyright notice
  23. and this notice must be preserved on all copies.  */
  24.  
  25.  
  26. /* This file contains all the code needed for the program `collect'.
  27.  
  28.    `collect' is run on all object files that are processed
  29.    by GNU C++, to create a list of all the file-level
  30.    initialization and destruction that need to be performed.
  31.    It generates an assembly file which holds the tables
  32.    which are walked by the global init and delete routines.
  33.    The format of the tables are an integer length,
  34.    followed by the list of function pointers for the
  35.    routines to be called.
  36.  
  37.    Constructors are called in the order they are laid out
  38.    in the table.  Destructors are called in the reverse order
  39.    of the way they lie in the table.  */
  40.  
  41. #include "config.h"
  42. int target_flags;    /* satisfy dependency in config.h */
  43.  
  44. #ifndef USE_COLLECT
  45. main()
  46. {
  47.   exit(0);
  48. }
  49.  
  50. #else
  51.  
  52.  
  53. #include <sys/types.h>
  54. #include <sys/stat.h>
  55.  
  56. #include <stdio.h>
  57. #include <a.out.h>
  58. #include <ar.h>
  59.  
  60. #ifdef UMAX
  61. #include <sgs.h>
  62. #endif
  63.  
  64. /*
  65.  *    Define various output routines in terms on ASM_INT_OP,
  66.  *    which should be defined in config.h -- if it's not, add it
  67.  *    as the marker used to allocate an int on your architecture.
  68.  */
  69. #ifdef i386
  70. #define ASM_INT_OP    ASM_LONG
  71. #define NO_UNDERSCORES 1
  72. #endif
  73.  
  74. #ifndef ASM_OUTPUT_INT_CONST
  75. #define ASM_OUTPUT_INT_CONST(FILE,VALUE)    \
  76.   fprintf(FILE,"\t%s %d\n", ASM_INT_OP, VALUE)
  77. #endif
  78.  
  79. #ifndef ASM_OUTPUT_LABELREF_AS_INT
  80. #define ASM_OUTPUT_LABELREF_AS_INT(FILE,NAME)    \
  81.   (fprintf(FILE,"\t%s", ASM_INT_OP), \
  82.    ASM_OUTPUT_LABELREF(FILE,NAME), \
  83.    fprintf(FILE,"\n"))
  84. #endif
  85.  
  86. #ifndef ASM_OUTPUT_PTR_INT_SUM
  87. #define ASM_OUTPUT_PTR_INT_SUM(FILE,NAME,VALUE)    \
  88.   (fprintf(FILE,"\t%s", ASM_INT_OP), \
  89.    ASM_OUTPUT_LABELREF(FILE,NAME), \
  90.    fprintf(FILE,"+%d\n", VALUE))
  91. #endif
  92.  
  93. #ifndef ASM_OUTPUT_SOURCE_FILENAME
  94. #define ASM_OUTPUT_SOURCE_FILENAME(FILE,NAME)\
  95.   fprintf (FILE, "\t.file\t\"%s\"\n", NAME);
  96. #endif
  97.  
  98. extern int xmalloc ();
  99. extern void free ();
  100.  
  101. #ifndef CTOR_TABLE_NAME
  102. #define CTOR_TABLE_NAME "__CTOR_LIST__"
  103. #endif
  104.  
  105. #ifndef DTOR_TABLE_NAME
  106. #define DTOR_TABLE_NAME "__DTOR_LIST__"
  107. #endif
  108.  
  109. /*    Define or undef this in your config.h. Should be defined for
  110.  *    MIPS & Sun-386i.
  111.  */
  112.  
  113. #ifdef NO_UNDERSCORES
  114. #  ifndef CTOR_DTOR_MARKER_NAME
  115. #    ifndef NO_DOLLAR_IN_LABEL
  116. #      define CTOR_DTOR_MARKER_NAME "_GLOBAL_$"
  117. #    else
  118. #      define CTOR_DTOR_MARKER_NAME "_GLOBAL_."
  119. #    endif
  120. #    define CTOR_DTOR_MARKER_LENGTH 9
  121. #    define CTOR_DTOR_MARKER_OFFSET 0
  122. #  endif
  123. #else
  124. #  ifndef CTOR_DTOR_MARKER_NAME
  125. #    ifndef NO_DOLLAR_IN_LABEL
  126. #      define CTOR_DTOR_MARKER_NAME "__GLOBAL_$"
  127. #    else
  128. #      define CTOR_DTOR_MARKER_NAME "__GLOBAL_."
  129. #    endif
  130. #    define CTOR_DTOR_MARKER_LENGTH 10
  131. #    define CTOR_DTOR_MARKER_OFFSET 1
  132. #  endif
  133. #endif
  134.  
  135. enum error_code { OK, BAD_MAGIC, NO_NAMELIST,
  136.           FOPEN_ERROR, FREAD_ERROR, FWRITE_ERROR,
  137.           RANDOM_ERROR, };
  138.  
  139. enum error_code process ();
  140. enum error_code process_a (), process_o ();
  141. enum error_code output_ctor_dtor_table ();
  142. void assemble_name ();
  143.  
  144. /* Files for holding the assembly code for table of constructor
  145.    function pointer addresses and list of destructor
  146.    function pointer addresses.  */
  147. static FILE *outfile;
  148.  
  149. /* Default outfile name, or take name from argv with -o option.  */
  150. static char *outfile_name = "a.out";
  151.  
  152. /* For compatibility with toplev.c and tm-sun386.h  */
  153. char *dump_base_name;
  154. int optimize = 0;
  155. char *language_string = "GNU C++";
  156. char *main_input_filename;
  157.  
  158. /*
  159.  * The list of constructors & destructors. We process all files & then
  160.  * spit these out in output_ctor_dtor_table(), because we need to know
  161.  *  the length of the list.
  162.  */
  163.  
  164. struct ctor_dtor_list_elem
  165. {
  166.   struct ctor_dtor_list_elem *next;
  167.   char *name;
  168. } *dtor_chain, *ctor_chain;
  169.  
  170. int dtor_chain_length = 0;
  171. int ctor_chain_length = 0;
  172.  
  173. main (argc, argv)
  174.      int argc;
  175.      char *argv[];
  176. {
  177.   int i, nerrs = 0;
  178.   enum error_code code;
  179.   FILE *fp;
  180.  
  181.   if (argc > 2 && !strcmp (argv[1], "-o"))
  182.     {
  183.       outfile_name = argv[2];
  184.       i = 3;
  185.     }
  186.   else
  187.     i = 1;
  188.  
  189.   if ((outfile = fopen (outfile_name, "w")) == NULL)
  190.     {
  191.       perror ("collect");
  192.       exit (-1);
  193.     }
  194.  
  195.   dump_base_name = main_input_filename = outfile_name;
  196.   for (; i < argc; i++)
  197.     {
  198.       char buf[80];
  199.  
  200.       /* This is a library, skip it.  */
  201.       if (argv[i][0] == '-' && argv[i][1] == 'l')
  202.     continue;
  203.  
  204.       if ((fp = fopen (argv[i], "r")) == NULL)
  205.     {
  206.       sprintf (buf, "collect `%s'", argv[i]);
  207.       perror (buf);
  208.       exit (-1);
  209.     }
  210.  
  211.       switch (code = process (fp, argv[i]))
  212.     {
  213.     case OK:
  214.       break;
  215.  
  216.     case BAD_MAGIC:
  217.       fprintf (stderr, "file `%s' has a bad magic number for collect\n",
  218.            argv[i]);
  219.       exit (-1);
  220.  
  221.     case NO_NAMELIST:
  222.       fprintf (stderr, "file `%s' has a no namelist for collect\n",
  223.            argv[i]);
  224.       exit (-1);
  225.  
  226.     case RANDOM_ERROR:
  227.       fprintf (stderr, "random error while processing file `%s':\n",
  228.            argv[i]);
  229.       perror ("collect");
  230.       exit (-1);
  231.  
  232.     case FOPEN_ERROR:
  233.       fprintf (stderr, "fopen(3S) error while processing file `%s' in collect\n",
  234.            argv[i]);
  235.       exit (-1);
  236.  
  237.     case FREAD_ERROR:
  238.       fprintf (stderr, "fread(3S) error while processing file `%s' in collect\n",
  239.            argv[i]);
  240.       exit (-1);
  241.  
  242.     case FWRITE_ERROR:
  243.       fprintf (stderr, "fwrite(3S) error while processing file `%s' in collect\n",
  244.            argv[i]);
  245.       exit (-1);
  246.  
  247.     default:
  248.       abort ();
  249.     }
  250.  
  251.       fclose (fp);
  252.  
  253.     }
  254.  
  255.   switch (code = output_ctor_dtor_table ())
  256.     {
  257.     case OK:
  258.       fclose (outfile);
  259.       exit (0);
  260.     case FREAD_ERROR:
  261.       perror ("fread(3S) failed in collect, at end");
  262.       break;
  263.     case FWRITE_ERROR:
  264.       perror ("fwrite(3S) failed in collect, at end");
  265.       break;
  266.     case FOPEN_ERROR:
  267.       perror ("fopen(3S) failed in collect, at end");
  268.       break;
  269.     case RANDOM_ERROR:
  270.       fprintf (stderr, "random error in collect, at end");
  271.       break;
  272.     }
  273.   exit (-1);
  274. }
  275.  
  276. void
  277.   add_ctor_dtor_elem(symbol_name)
  278. char *symbol_name;
  279. {
  280.   /*
  281.    *    In EXTENDED_COFF systems, it's possible to
  282.    *    have multiple occurances of symbols ( or so it
  283.    *    appears) in the symbol table. Sooo, we scan to
  284.    *    eliminate duplicate entries. This can never hurt,
  285.    *    and helps EXTENDED_COFF.
  286.    */
  287.   int exists;
  288.   int is_ctor = (symbol_name[CTOR_DTOR_MARKER_LENGTH] == 'I');
  289.   
  290.   struct ctor_dtor_list_elem *p
  291.     = ((is_ctor) ? ctor_chain : dtor_chain);
  292.   
  293.   exists = 0;
  294.   while (p) {
  295.     if (strcmp( symbol_name, p -> name ) == 0 ) {
  296.       exists = 1;
  297.       break;
  298.     }
  299.     p = p -> next;
  300.   }
  301.   if ( ! exists ) {
  302.     
  303.     struct ctor_dtor_list_elem *new = (struct ctor_dtor_list_elem *)
  304.       xmalloc(sizeof(struct ctor_dtor_list_elem));
  305.     
  306.     new->name = (char *)xmalloc (strlen (symbol_name)
  307.                  + CTOR_DTOR_MARKER_OFFSET + 2);
  308.     
  309.     strcpy(new -> name, symbol_name + CTOR_DTOR_MARKER_OFFSET);
  310.     
  311.     if ( is_ctor ) {
  312.       new -> next = ctor_chain;
  313.       ctor_chain = new;
  314.       ctor_chain_length++;
  315.     }
  316.     else {
  317.       new->next = dtor_chain;
  318.       dtor_chain = new;
  319.       dtor_chain_length++;
  320.     }
  321.   }
  322. }
  323.  
  324.  
  325. enum error_code
  326. output_ctor_dtor_table ()
  327. {
  328.   int dtor_offset;
  329.  
  330.   /* Write out the CTOR tabel */
  331.   ASM_FILE_START(outfile);
  332.  
  333.   fprintf (outfile, "%s\n", TEXT_SECTION_ASM_OP);
  334.   ASM_GLOBALIZE_LABEL (outfile, CTOR_TABLE_NAME);
  335.   ASM_OUTPUT_LABEL (outfile, CTOR_TABLE_NAME);
  336.   ASM_OUTPUT_INT_CONST(outfile,ctor_chain_length);
  337.   while ( ctor_chain ) {
  338.     ASM_OUTPUT_LABELREF_AS_INT (outfile, ctor_chain->name);
  339.     ctor_chain = ctor_chain -> next;
  340.   }
  341.   /* NULL-terminate the list of constructors.  -- not needed, but keep it */
  342.   ASM_OUTPUT_INT_CONST (outfile, 0);
  343.  
  344.   /*
  345.    * Now, lay out the destructors
  346.    */
  347.  
  348.   fprintf (outfile, "%s\n", DATA_SECTION_ASM_OP);
  349.   ASM_GLOBALIZE_LABEL (outfile, DTOR_TABLE_NAME);
  350.   ASM_OUTPUT_LABEL (outfile, DTOR_TABLE_NAME);
  351.   ASM_OUTPUT_INT_CONST(outfile,dtor_chain_length);
  352.   while (dtor_chain)
  353.     {
  354.       ASM_OUTPUT_LABELREF_AS_INT (outfile, dtor_chain->name);
  355.       dtor_chain = dtor_chain->next;
  356.     }
  357.   ASM_OUTPUT_INT_CONST (outfile, 0);
  358.   ASM_OUTPUT_INT_CONST (outfile, 0);
  359.  
  360.   fclose (outfile);
  361.   return OK;
  362. }
  363.  
  364.  
  365. /*****************************************************************************
  366.  *    
  367.  *        COFF & EXTENDED COFF
  368.  *    
  369.  ****************************************************************************/
  370. #if defined(COFF) || defined(EXTENDED_COFF)
  371.  
  372. #include <ldfcn.h>
  373.  
  374. #if defined(EXTENDED_COFF)
  375. #   define GCC_SYMBOLS(X) (SYMHEADER(X).isymMax+SYMHEADER(X).iextMax)
  376. #   define GCC_SYMENT SYMR
  377. #   define GCC_OK_SYMBOL(X) ((X).st == stProc &&  (X).sc == scText)
  378. #   define GCC_SYMINC(X) (1)
  379. #else
  380. #   define GCC_SYMBOLS(X) (HEADER(ldptr).f_nsyms)
  381. #   define GCC_SYMENT SYMENT
  382. #ifndef UNUSUAL_COFF_DEFINITION
  383. #   define GCC_OK_SYMBOL(X) (!(((X).n_type & N_TMASK) != (DT_NON << N_BTSHFT)))
  384. #else
  385. #   define GCC_OK_SYMBOL(X) ((X).n_scnum == 1 && (X).n_sclass == C_EXT)
  386. #endif
  387. #   define GCC_SYMINC(X) ((X).n_numaux+1)
  388. #endif
  389.  
  390. enum error_code
  391.   process (fp, filename)
  392. FILE *fp;
  393. char *filename;
  394. {
  395.   LDFILE *ldptr = NULL;
  396.   do {
  397.     if ((ldptr = ldopen(filename, ldptr)) != NULL ) {
  398.       
  399.       if (!ISCOFF( HEADER(ldptr).f_magic ) ) {
  400.     return BAD_MAGIC;
  401.       }
  402.       else {
  403.     
  404.     int symbols = GCC_SYMBOLS(ldptr);
  405.     int symindex;
  406.     
  407.     for (symindex = 0;
  408.          symindex < symbols;
  409.          ) {
  410.       
  411.       GCC_SYMENT symbol;
  412.       
  413.       char *symbol_name;
  414.       extern char *ldgetname();
  415.       int returnCode;
  416.       
  417.       returnCode = ldtbread(ldptr, symindex, &symbol);
  418.       
  419.       if ( returnCode <= 0 ) {
  420.         break;
  421.       }
  422.       
  423.       symindex += GCC_SYMINC(symbol);
  424.       
  425.       if (! GCC_OK_SYMBOL(symbol)) continue;
  426.       symbol_name = ldgetname(ldptr, &symbol);
  427.       
  428.       /* Check to see if we have a CTOR/DTOR marker  */
  429.  
  430.       if (! strncmp (CTOR_DTOR_MARKER_NAME, symbol_name,
  431.              CTOR_DTOR_MARKER_LENGTH))
  432.         add_ctor_dtor_elem(symbol_name);
  433.     }
  434.       }
  435.     }
  436.     else {
  437.       return( RANDOM_ERROR );
  438.     }
  439.   } while ( ldclose(ldptr) == FAILURE ) ;
  440.   return ( OK );
  441. }
  442.  
  443. /****** taken from sdbout.c ******/
  444.  
  445.  
  446. /* Tell the assembler the source file name.
  447.    On systems that use SDB, this is done whether or not -g,
  448.    so it is called by ASM_FILE_START.
  449.  
  450.    ASM_FILE is the assembler code output file,
  451.    INPUT_NAME is the name of the main input file.  */
  452.  
  453. /* void */
  454. sdbout_filename (asm_file, input_name)
  455.      FILE *asm_file;
  456.      char *input_name;
  457. {
  458.   int len = strlen (input_name);
  459.   char *na = input_name + len;
  460.  
  461.   /* NA gets INPUT_NAME sans directory names.  */
  462.   while (na > input_name)
  463.     {
  464.       if (na[-1] == '/')
  465.     break;
  466.       na--;
  467.     }
  468.  
  469.   ASM_OUTPUT_SOURCE_FILENAME (asm_file, na);
  470. }
  471.  
  472. #else
  473.  
  474. /*****************************************************************************
  475.  *    
  476.  *        BSD SYMBOL TABLES
  477.  *    
  478.  *****************************************************************************/
  479.  
  480. /* Figure out the type of file we need to process.
  481.    Currently, only .o and .a formats are acceptable.  */
  482. enum error_code
  483. process (fp, filename)
  484.      FILE *fp;
  485.      char *filename;
  486. {
  487.   struct stat file_stat;
  488.   union
  489.     {
  490.       char ar_form[SARMAG];
  491.       struct exec a_out_form;
  492.     } header;
  493.   int size;
  494.  
  495.   if (fstat (fp->_file, &file_stat))
  496.     return RANDOM_ERROR;
  497.  
  498.   size = file_stat.st_size;
  499.  
  500.   if (fread (header.ar_form, SARMAG, 1, fp) < 1)
  501.     return RANDOM_ERROR;
  502.  
  503.   if (strncmp (ARMAG, header.ar_form, SARMAG))
  504.     {
  505.       fseek (fp, 0, 0);
  506.       if (fread (&header.a_out_form, sizeof (struct exec), 1, fp) < 1)
  507.     return RANDOM_ERROR;
  508.  
  509.       if (N_BADMAG (header.a_out_form))
  510.     return BAD_MAGIC;
  511.  
  512.       return process_o (fp, &header.a_out_form, size);
  513.     }
  514.   return process_a (fp);
  515. }
  516.  
  517. enum error_code
  518. process_o (fp, header, size)
  519.      FILE *fp;
  520.      struct exec *header;
  521.      int size;
  522. {
  523.   int symoff, symend;
  524. #ifndef hp9000s300
  525.   struct nlist *nelem, *nelems, *nend;
  526.   char *strtab;
  527. #else
  528.   struct nlist_ *nelem, *nelems, *nend;
  529. #endif /* hp9000s300 */
  530.  
  531.   if (N_BADMAG (*header))
  532.     return BAD_MAGIC;
  533.  
  534. #ifndef hp9000s300
  535.   symoff = N_SYMOFF (*header);
  536.   symend = N_STROFF (*header);
  537. #else
  538.   symoff = LESYM_OFFSET (*header);
  539.   symend = DNTT_OFFSET (*header);
  540. #endif /* hp9000s300 */
  541.   if (symoff == symend)
  542.     return NO_NAMELIST;
  543.   fseek (fp, symoff - sizeof (struct exec), 1);
  544. #ifndef hp9000s300
  545.   nelems = (struct nlist *)alloca (symend - symoff);
  546. #else
  547.   nelems = (struct nlist_ *)alloca (symend - symoff);
  548. #endif /* hp9000s300 */
  549.   if (fread (nelems, sizeof (char), symend - symoff, fp) < symend - symoff)
  550.     return FREAD_ERROR;
  551.  
  552. #ifndef hp9000s300
  553.   strtab = (char *)alloca ((char *)size - (char *)symend);
  554.   if (fread (strtab, sizeof (char), (char *)size - (char *)symend, fp)
  555.       < ((char *)size - (char *)symend) * sizeof (char))
  556.     return FREAD_ERROR;
  557.  
  558.   nend = (struct nlist *)((char *)nelems + symend - symoff);
  559.   for (nelem = nelems; nelem < nend; nelem++)
  560. #else
  561.   nend = (struct nlist_ *)((char *)nelems + symend - symoff);
  562.   for (nelem = nelems; nelem < nend; )
  563. #endif /* hp9000s300 */
  564.     {
  565. #ifndef hp9000s300
  566.       int strindex = nelem->n_un.n_strx;
  567. #else
  568.       int symlen = nelem->n_length;
  569.       char p[255];
  570.       memcpy(p, (char *) (++nelem), symlen);
  571.       p[symlen]='\0';
  572.      
  573.       /* printf("'%s'\n",p);   */
  574. #endif /* hp9000s300 */
  575.  
  576. #ifndef hp9000s300
  577.       if (strindex)
  578. #else
  579.       nelem   = (struct nlist_ *)((char *)nelem + symlen);
  580.       
  581.       if (symlen)
  582. #endif /* hp9000s300 */
  583.     {
  584. #ifndef hp9000s300
  585.       char *p = strtab+strindex;
  586. #endif /* hp9000s300 */
  587.  
  588.       if (! strncmp ("__GLOBAL_$", p, 10))
  589.         add_ctor_dtor_elem(p);
  590.     }
  591.     }
  592.   return OK;
  593. }
  594.  
  595. enum error_code
  596. process_a (fp)
  597.      FILE *fp;
  598. {
  599.   struct ar_hdr header;
  600.   struct exec exec_header;
  601.   int size;
  602.   enum error_code code;
  603.  
  604.   while (! feof (fp))
  605.     {
  606.       char c;
  607. #ifdef hp9000s300
  608.       int curpos;
  609. #endif /* hp9000s300 */
  610.  
  611.       if (fread (&header, sizeof (struct ar_hdr), 1, fp) < 1)
  612.     return RANDOM_ERROR;
  613.  
  614.       size = atoi (header.ar_size);
  615. #ifdef hp9000s300
  616.       curpos = ftell(fp);
  617. #endif /* hp9000s300 */
  618.  
  619. #ifndef hp9000s300
  620.       if (fread (&exec_header, sizeof (struct exec), 1, fp) < 1)
  621.     return RANDOM_ERROR;
  622. #else
  623.       /* if the name starts with /, it's an index file */
  624.       if (header.ar_name[0] != '/') {
  625.       
  626.         if (fread (&exec_header, sizeof (struct exec), 1, fp) < 1)
  627.       return RANDOM_ERROR;
  628. #endif /* hp9000s300 */
  629.  
  630.       code = process_o (fp, &exec_header, size);
  631.       if (code != OK)
  632.     return code;
  633. #ifdef hp9000s300
  634.       } 
  635.       
  636.       if (fseek(fp,(long) curpos + size,0))
  637.     return RANDOM_ERROR;
  638. #endif /* hp9000s300 */
  639.       if ((c = getc (fp)) == '\n')
  640.     ;
  641.       else
  642.     ungetc (c, fp);
  643.       c = getc (fp);
  644.       if (c != EOF)
  645.     ungetc (c, fp);
  646.     }
  647.   return OK;
  648. }
  649. #endif
  650.  
  651. /* Output to FILE a reference to the assembler name of a C-level name NAME.
  652.    If NAME starts with a *, the rest of NAME is output verbatim.
  653.    Otherwise NAME is transformed in an implementation-defined way
  654.    (usually by the addition of an underscore).
  655.    Many macros in the tm file are defined to call this function.
  656.  
  657.    Swiped from `varasm.c'  */
  658.  
  659. void
  660. assemble_name (file, name)
  661.      FILE *file;
  662.      char *name;
  663. {
  664.   if (name[0] == '*')
  665.     fputs (&name[1], file);
  666.   else
  667. #ifdef NO_UNDERSCORES
  668.     fprintf (file, "%s", name);
  669. #else
  670.     fprintf (file, "_%s", name);
  671. #endif
  672. }
  673.  
  674. int
  675. xmalloc (size)
  676.      int size;
  677. {
  678.   int result = malloc (size);
  679.   if (! result)
  680.     {
  681.       fprintf (stderr, "Virtual memory exhausted\n");
  682.       exit (-1);
  683.     }
  684.   return result;
  685. }
  686. #endif
  687.